package com.lingyun.framework.aspect;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.lingyun.common.annotation.Log;
import com.lingyun.common.mapper.LyLogMapper;
import com.lingyun.common.pojo.LyLog;
import com.lingyun.common.utils.ServletUtils;
import com.lingyun.common.utils.ip.IpUtils;
import com.lingyun.common.utils.security.SecurityUtils;
import com.lingyun.common.vo.LoginUser;
import eu.bitwalker.useragentutils.Browser;
import eu.bitwalker.useragentutils.OperatingSystem;
import eu.bitwalker.useragentutils.UserAgent;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Arrays;
import java.util.Date;
import java.util.Objects;
import static com.lingyun.common.utils.ServletUtils.getRequest;

/**
 * 日志自定义注解
 *
 * @author 没事别学JAVA
 */
@Aspect
@Component
public class LogAspect {


    private static final Logger log = LoggerFactory.getLogger(LogAspect.class);

    // 需要获取登录信息的，业务类型
    public static final String[] BUSINESS_TYPE_NUMBERS = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"};

    @Resource
    LyLogMapper lyLogMapper;


    /**
     * /**
     * * 业务逻辑正常时执行
     *
     * @param joinPoint     切点
     * @param controllerLog 注解
     * @param jsonResult    访问目标的返回值
     */
    @AfterReturning(pointcut = "@annotation(controllerLog)", returning = "jsonResult")        //@annotation声明以注解的方式来定义切点
    public void doAfterReturning(JoinPoint joinPoint, Log controllerLog, Object jsonResult) {
        System.out.println("日志业务逻辑开始执行之前执行.......");
        handleLog(joinPoint, controllerLog, null, jsonResult); // 日志处理

    }


    /**
     * 异常时时执行
     *
     * @param joinPoint     切点
     * @param controllerLog 注解
     * @param e             异常
     */
    @AfterThrowing(pointcut = "@annotation(controllerLog)", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, Log controllerLog, Exception e) {
        System.out.println("日志异常时时执行之前执行.......");
        handleLog(joinPoint, controllerLog, e, null); // 日志处理
    }


    /**
     * 日志处理
     *
     * @param joinPoint     切点
     * @param controllerLog 自定义日志注解
     * @param e             异常
     * @param jsonResult    访问目标的返回值
     */
    protected void handleLog(final JoinPoint joinPoint, Log controllerLog, final Exception e, Object jsonResult) {

        // 设置日志数据
        LyLog lyLog = new LyLog();
        lyLog.setLogOperationStatus("1"); // 设置日志操作状态--正常

        try {
            // 获取客户端ip
            String ip = IpUtils.getClientIp(getRequest());
            // 解析agent字符串
            UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent"));
            //获取浏览器对象
            Browser browser = userAgent.getBrowser();
            //获取操作系统对象
            OperatingSystem operatingSystem = userAgent.getOperatingSystem();
            // 获取客户端浏览器
            String browserName = browser.getName();
            // 获取客户端操作系统
            String os = operatingSystem.getName();
            // 获取真实地址
            String address = IpUtils.getRealAddressByIP(ip);
            // 获取方法名
            String className = joinPoint.getTarget().getClass().getName();
            String methodName = joinPoint.getSignature().getName();

            // 获取日志模块
            String title = controllerLog.title();
            // 获取业务类型
            String businessType = controllerLog.businessType();
            // 获取日志描述
            String description = controllerLog.description();
            // 获取请求方式
            String methodRequest = ServletUtils.getRequest().getMethod();
            // 获取请求url
            String requestUrl = ServletUtils.getRequest().getRequestURI();

            // 如果是登录 注册，无需查询用户信息
            String accountNumber = "";
            String nickName = "";
            String userType = "";
            if(businessType != null && Arrays.asList(BUSINESS_TYPE_NUMBERS).contains(businessType)){
                // 获取到当前用户
                LoginUser loginUser = SecurityUtils.getLoginUser();
                // 获取当前操作用户账号
                accountNumber = loginUser.getLyUser().getUserName();
                // 获取当前操作用户昵称
                nickName = loginUser.getLyUser().getNickName();
                // 获取当前用户类型
                userType = loginUser.getLyUser().getUserType();
            }

            lyLog.setLogTitle(title);
            lyLog.setLogBusinessType(businessType);
            lyLog.setRequestMode(methodRequest);
            lyLog.setMethodName(className + "." + methodName + "()");
            lyLog.setLogOperationName(accountNumber);
            lyLog.setLogOperationNickName(nickName);
            lyLog.setUserType(userType);
            lyLog.setLogOperationUrl(requestUrl);
            lyLog.setBrowser(browserName);
            lyLog.setLogOperationIp(ip);
            lyLog.setLogOperLocation(address);
            lyLog.setOs(os);

            // 获取异常
            if (e != null) {
                lyLog.setLogOperationStatus("2"); // 设置日志操作状态--正常
                String errorMsg = StringUtils.substring(e.getMessage(), 0, 2000);
                lyLog.setErrorMsg(errorMsg);
            }
            // 获取访问目标的返回值
            if (ObjectUtil.isNotNull(jsonResult)) {
                String successJson = StringUtils.substring(JSONUtil.toJsonStr(jsonResult), 0, 2000);
                lyLog.setJsonResult(successJson);
            }
            lyLog.setLogDescription(description);
            lyLog.setLogOperationDate(new Date());
            lyLogMapper.insertSelective(lyLog);

        } catch (Exception ex) {
            // 记录本地异常日志
            log.error("==前置通知异常==");
            log.error("异常信息:{}", ex.getMessage());
            ex.printStackTrace();
        }

    }


}
